#include "PhotonBucket.h"
#include <trax.hpp>
#include "atAtomicReg.h"
#include "MemoryManager.h"

namespace AtomTrace
{
	PhotonBucket::PhotonBucket():
		current(0),
        cur_offset(0)
		//cur_stack(0)
	{
        pht_size = sizeof(Photon)/4;
        pm_start_addr = GetPhotonMapAddr();
	}

	const Photon & PhotonBucket::operator[](int index) const
	{
		if(current <= 0)
			printf("Error, photon bucket is empty\n");

		if(index < current)
		{
			return phts[index];
		}else
		{
			return phts[0];
		}

	}

    
	bool PhotonBucket::IsFull() const
	{ return (current >= PHT_STACK_CAP); }
    
	Photon & PhotonBucket::operator[](int index)
	{
		if(current <= 0)
			printf("Error, photon bucket is empty\n");

		if(index < current)
		{
			return phts[index];
		}else
		{
			return phts[0];
		}
	}

	bool PhotonBucket::StorePhoton(const Photon & iPht)
	{
		if(this->IsFull()) return false;
		phts[current] = iPht;
		current++;
		return true;
	}

	bool PhotonBucket::StorePhoton(const Color & iflux, const Vector3 & iPos, const Vector3 & idir)
	{
		if(this->IsFull()) return false;
		phts[current].flux = iflux;
		phts[current].pRay._o = iPos;
		phts[current].pRay._dir = idir;
		current++;
		return true;
	}

	bool PhotonBucket::StoreIntoMemory(int addr)
	{
		//int phtsize = sizeof(Photon) / 4;
		for(int i=0; i<PHT_STACK_CAP; i++)
		{
			phts[i].SaveToMemory(addr + i*pht_size);
		}

		return true;
	}
    
    bool PhotonBucket::StoreIntoMemory()
    {
        /**/
        cur_offset = atomicadd(REG_PHT_ST_ID, PHT_STACK_CAP) - PHT_STACK_CAP;
        //printf("test 10 is %d\n", 10);
        //printf("cur_offset is %d\n", cur_offset);
        //printf("Photon bucket size is %d\n", PHT_STACK_CAP);
        if(cur_offset + PHT_STACK_CAP > (pm_start_addr+1 + GetMaxNumberOfPhotons() * pht_size))
        {
            printf("Error, saving photons out of photon map capacity!!\n");
            return false;
        }
        for (int i=0; i<PHT_STACK_CAP; i++) {
            phts[i].SaveToMemory(pm_start_addr+1 + (cur_offset+i)*pht_size);
        }
         // **/
        /**
        for (int i=0; i<PHT_STACK_CAP; i++) {
            cur_offset = atomicinc(REG_PHT_ST_ID);
            if(cur_offset == 0)
            {
                printf("In pbk store into memory, photon[0] is\n");
                phts[i].DebugPrint();
            }
            phts[i].SaveToMemory(pm_start_addr+1 + cur_offset*pht_size);
        }
        // **/
        
        return true;
    }

	bool PhotonBucket::StoreNonEmptyIntoMem(int addr)
	{
		//int phtsize = sizeof(Photon) / 4;
		for(int i=0; i<current; i++)
		{
			phts[i].SaveToMemory(addr + i*pht_size);
		}

		return true;
	}
    
    bool PhotonBucket::StoreNonEmptyIntoMem()
    {
        if(current == 0) return true;
        /**/
        cur_offset = atomicadd(REG_PHT_ST_ID, current) - current;
        for (int i=0; i<current; i++) {
            phts[i].SaveToMemory(pm_start_addr+1 + (cur_offset+i)*pht_size);
        }
         // **/
        /**
        for (int i=0; i<current; i++) {
            cur_offset = atomicinc(REG_PHT_ST_ID);
            phts[i].SaveToMemory(pm_start_addr+1 + cur_offset*pht_size);
        }
        // **/
        
        return true;
    }

    bool PhotonBucket::LoadPhotonsFromGM(const int addr)
    {
    	for(int i=0; i<PHT_STACK_CAP; i++)
    	{
    		phts[i].LoadFromMemory(addr + i*pht_size);
    	}
    	current = PHT_STACK_CAP;
    	return true;
    }

    bool PhotonBucket::LoadPhotonsFromGM(const int addr, const int num)
    {
    	if(num < 1) return true;
    	if(num >= PHT_STACK_CAP) return false;

    	for(int i=0; i<num; i++)
    	{
    	    phts[i].LoadFromMemory(addr + i*pht_size);
    	}
    	current = num;
    	return true;
    }
}
